package niu.toy.spring.mvc.impl;


import niu.toy.spring.mvc.HandlerArgumentResolver;
import niu.toy.spring.mvc.HandlerMethodParameter;
import niu.toy.spring.mvc.ModelAndViewContainer;
import niu.toy.spring.mvc.NativeWebRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ArgumentResolverComposite implements HandlerArgumentResolver {
    private static final Logger logger = LoggerFactory.getLogger(ArgumentResolverComposite.class);

    private final List<HandlerArgumentResolver> argumentResolvers = new LinkedList<>();

    private final Map<HandlerMethodParameter, HandlerArgumentResolver> argumentResolverCache =
            new ConcurrentHashMap<>(256);



    public ArgumentResolverComposite addResolver(HandlerArgumentResolver resolver) {
        this.argumentResolvers.add(resolver);
        return this;
    }


    public ArgumentResolverComposite addResolvers( HandlerArgumentResolver... resolvers) {
        if (resolvers != null) {
            for (HandlerArgumentResolver resolver : resolvers) {
                this.argumentResolvers.add(resolver);
            }
        }
        return this;
    }


    public ArgumentResolverComposite addResolvers(List<? extends HandlerArgumentResolver> resolvers) {
        if (resolvers != null) {
            for (HandlerArgumentResolver resolver : resolvers) {
                this.argumentResolvers.add(resolver);
            }
        }
        return this;
    }

    /**
     * 返回只读参数解析器列表
     */
    public List<HandlerArgumentResolver> getResolvers() {
        return Collections.unmodifiableList(this.argumentResolvers);
    }

    public void clear() {
        this.argumentResolvers.clear();
    }



    @Override
    public boolean supportsParameter(HandlerMethodParameter parameter) {
        return (getArgumentResolver(parameter) != null);
    }


    
    public Object resolveArgument(HandlerMethodParameter parameter, NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception {

        HandlerArgumentResolver resolver = getArgumentResolver(parameter);
        if (resolver == null) {
            throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
        }
        return resolver.resolveArgument(parameter, request,mavContainer);
    }

    
    private HandlerArgumentResolver getArgumentResolver(HandlerMethodParameter parameter) {
        HandlerArgumentResolver result = this.argumentResolverCache.get(parameter);
        if (result == null) {
            for (HandlerArgumentResolver methodArgumentResolver : this.argumentResolvers) {

                if (methodArgumentResolver.supportsParameter(parameter)) {
                    result = methodArgumentResolver;
                    this.argumentResolverCache.put(parameter, result);
                    break;
                }
            }
        }
        return result;
    }
}
